home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / Font.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  16.3 KB  |  565 lines  |  [TEXT/CWIE]

  1. // Font.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import java.net.URL;
  8. import java.awt.image.FilteredImageSource;
  9. import java.awt.image.CropImageFilter;
  10. import java.awt.image.ImageFilter;
  11.  
  12. import netscape.util.*;
  13.  
  14. /** Object subclass representing a Font.
  15.   */
  16.  
  17.  
  18. public class Font implements Codable {
  19.     FontMetrics                 _metrics;
  20.     String                      _name;
  21.     URL                         _url;
  22.     Bitmap                      _glyphsImage;
  23.     Vector                      _glyphVector, _widthsVector;
  24.     Hashtable                   _description;
  25.     java.awt.Font               _awtFont;
  26.     int                         _type, _widthsArrayBase, _widthsArray[];
  27.  
  28.     final static int            INVALID = 0, AWT = 1, DOWNLOADED = 2;
  29.  
  30.     /** Plain font style. */
  31.     public final static int     PLAIN = java.awt.Font.PLAIN;
  32.     /** Bold font style. */
  33.     public final static int     BOLD = java.awt.Font.BOLD;
  34.     /** Italic font style. */
  35.     public final static int     ITALIC = java.awt.Font.ITALIC;
  36.  
  37.     final static String         FAMILY = "Family", STYLE = "Style",
  38.                                 SIZE = "Size", WIDTHS = "Widths";
  39.     final static String         DESCRIPTION = "Description",
  40.                                 GLYPHS = "glyphs.gif";
  41.  
  42.     final static String         NAME_KEY = "name";
  43.     final static String         STYLE_KEY = "style";
  44.     final static String         SIZE_KEY = "size";
  45.     private static Class fontClass;
  46.  
  47.     private static Class fontClass() {
  48.         if (fontClass == null) {
  49.             fontClass = new Font().getClass();
  50.         }
  51.  
  52.         return fontClass;
  53.     }
  54.  
  55.     /** Constructs an empty Font. This constructor is only useful when
  56.       * decoding.
  57.       */
  58.     public Font() {
  59.         super();
  60.         _type = INVALID;
  61.     }
  62.  
  63.     /** Constructs a Font with the specified name, style and size.
  64.       */
  65.     public Font(String name, int style, int size) {
  66.         this();
  67.  
  68.         _awtFont = new java.awt.Font(name, style, size);
  69.         _name = name;
  70.         if (_awtFont != null) {
  71.             _type = AWT;
  72.         }
  73.     }
  74.  
  75.     /** Returns the "default" font, currently defined to be Helvetica 12.
  76.       */
  77.     public static Font defaultFont() {
  78.         return fontNamed("Helvetica", Font.PLAIN, 12);
  79.     }
  80.  
  81.     /** Retrieves the Font for the specified font name, style, and size, and
  82.       * places it in the Application's font cache, allowing future requests
  83.       * for the font to be handled efficiently.
  84.       */
  85.     public static synchronized Font fontNamed(String fontName, int style,
  86.                                               int size) {
  87.         Font font;
  88.         String uniqueName;
  89.         Application app;
  90.  
  91.         if (fontName == null || size == 0) {
  92.             return null;
  93.         }
  94.  
  95.         uniqueName = fontName + "." + style + "." + size;
  96.  
  97.         app = Application.application();
  98.         font = (Font)app.fontByName.get(uniqueName);
  99.  
  100.         if (font != null)
  101.             return font;
  102.  
  103.         font = new Font(fontName, style, size);
  104.         if (!font.isValid())
  105.             return null;
  106.  
  107.         app.fontByName.put(uniqueName, font);
  108.  
  109.         return font;
  110.     }
  111.  
  112.     /** Returns the Font identified by the String <b>aString</b>. Font names
  113.       * normally take the form "FontName:style:size". This is a convience for
  114.       * fontNamed() as the string is parsed apart and
  115.       * then fontNamed(name, style, size) is called.
  116.       */
  117.     public static Font fontNamed(String aString) {
  118.         String[]        fontDef;
  119.         String          fontName, fontStyleString;
  120.         char            firstChar;
  121.         int             fontSize, fontStyle;
  122.  
  123.         fontDef = stringsForString(aString);
  124.         if (fontDef == null || fontDef.length == 0) {
  125.             return null;
  126.         }
  127.  
  128.         fontName = fontDef[0];
  129.         if (fontName.equals("Default")) {
  130.             return defaultFont();
  131.         } else if (fontName.length() == 0) {
  132.             return null;
  133.         }
  134.  
  135.         /* if just a name, it's a downloadable font */
  136.         if (fontDef.length == 1) {
  137.             URL url;
  138.             Application app = Application.application();
  139.  
  140.             url = app._appResources.urlForFontNamed(fontName);
  141.             return getFontFromURL(url, fontName);
  142.         }
  143.  
  144.         fontStyleString = fontDef[1];
  145.         firstChar = fontStyleString.charAt(0);
  146.         if (firstChar == 'P' || firstChar == 'p') {
  147.             fontStyle = Font.PLAIN;
  148.         } else if (firstChar == 'B' || firstChar == 'b') {
  149.             fontStyle = Font.BOLD;
  150.         } else if (firstChar == 'I' || firstChar == 'i') {
  151.             fontStyle = Font.ITALIC;
  152.         } else {
  153.             try {
  154.                 fontStyle = Integer.parseInt(fontStyleString);
  155.             } catch (NumberFormatException e) {
  156.                 fontStyle = Font.PLAIN;
  157.             }
  158.         }
  159.  
  160.         fontSize = parseInt(fontDef[2]);
  161.         if (fontSize < 0) {
  162.             fontSize = 0;
  163.         }
  164.  
  165.         return fontNamed(fontName, fontStyle, fontSize);
  166.     }
  167.  
  168.     private static int parseInt(String s) {
  169.         try {
  170.             return Integer.parseInt(s);
  171.         } catch (NumberFormatException e) {
  172.             return 0;
  173.         }
  174.     }
  175.  
  176.     private static String[] stringsForString(String aString) {
  177.         Vector          stringVector;
  178.         String[]        strings;
  179.         String          string0, string1, string2;
  180.         StringBuffer    tmpBuffer;
  181.         int             i, count;
  182.  
  183.         if (aString == null) {
  184.             return null;
  185.         }
  186.  
  187.         if (aString.indexOf(':') == -1) {
  188.             strings = new String[1];
  189.             strings[0] = aString;
  190.             return strings;
  191.         }
  192.  
  193.         count = aString.length();
  194.         tmpBuffer = new StringBuffer();
  195.         stringVector = new Vector();
  196.         for (i = 0; i < count; i++) {
  197.             if (aString.charAt(i) == ':') {
  198.                 stringVector.addElement(tmpBuffer.toString());
  199.                 tmpBuffer = new StringBuffer();
  200.             } else {
  201.                 tmpBuffer.append(aString.charAt(i));
  202.             }
  203.         }
  204.         stringVector.addElement(tmpBuffer.toString());
  205.  
  206.         count = stringVector.count();
  207.         strings = new String[count];
  208.         for (i = 0; i < count; i++) {
  209.             strings[i] = (String)stringVector.elementAt(i);
  210.         }
  211.         return strings;
  212.     }
  213.  
  214.     // This is used in decoding.  Take a look at this again to see if it
  215.     // causes problems by having multiple fonts with the same name.  ALERT!
  216.  
  217.     synchronized void nameFont(String fontName, Font font) {
  218.         Application.application().fontByName.put(fontName, font);
  219.     }
  220.  
  221.     static synchronized Font getFontFromURL(URL absoluteURL, String fontName) {
  222.         Font font;
  223.         Application app = Application.application();
  224.  
  225.         if (absoluteURL == null) {
  226.             return null;
  227.         }
  228.  
  229.         if (fontName != null) {
  230.             font = (Font)app.fontByName.get(fontName);
  231.             if (font != null)
  232.                 return font;
  233.         }
  234.  
  235.         font = new Font(absoluteURL, fontName);
  236.         if (!font.isValid())
  237.             return null;
  238.  
  239.         app.fontByName.put(fontName, font);
  240.  
  241.         return font;
  242.     }
  243.  
  244.     /** Convenience constructor for instantiating a downloadable Font with
  245.       * the specified name and URL locating the Font's resources on the web
  246.       * server.
  247.       */
  248.     Font(java.net.URL fontURL, String name) {
  249.         this();
  250.  
  251.         URL                     configURL;
  252.         java.io.InputStream     inputStream;
  253.         Deserializer            deserializer;
  254.  
  255.         _url = fontURL;
  256.         _name = name;
  257.         _type = DOWNLOADED;
  258.  
  259.         _glyphVector = new Vector();
  260.         _widthsVector = new Vector();
  261.  
  262.       /* description file */
  263.         try {
  264.             configURL = new URL(fontURL, _name + ".font/" + DESCRIPTION);
  265.         } catch (Exception e) {
  266.             System.err.println(
  267.                 "Font.init() - Trouble creating font description URL " +
  268.                         fontURL + _name + ".font/" + DESCRIPTION + " : " + e);
  269.             _type = INVALID;
  270.             return;
  271.         }
  272.  
  273.         try {
  274.             inputStream = configURL.openStream();
  275.             deserializer = new Deserializer(inputStream);
  276.             _description = (Hashtable)deserializer.readObject();
  277.  
  278.             _loadWidths();
  279.         } catch (Exception e) {
  280.             System.err.println(
  281.                 "Font.init() - Trouble retrieving font description URL " +
  282.                                                     configURL);
  283.             e.printStackTrace(System.err);
  284.             _type = INVALID;
  285.             return;
  286.         }
  287.  
  288.       /* glyphs image */
  289.         _loadGlyphs(fontURL);
  290.     }
  291.  
  292.     void _loadWidths() {
  293.         Object    widthsInfo[];
  294.         int       i, count, index;
  295.  
  296.         if (_description == null) {
  297.             return;
  298.         }
  299.  
  300.         widthsInfo = (Object[])_description.get(WIDTHS);
  301.  
  302.         if (widthsInfo == null) {
  303.             System.err.println(
  304.                 "Font._loadWidths() - No widths information for " + _name);
  305.             return;
  306.         }
  307.  
  308.         _widthsArrayBase = parseInt((String)widthsInfo[0]);
  309.  
  310.         count = widthsInfo.length - 1;
  311.         _widthsArray = new int[_widthsArrayBase + count];
  312.         for (i = 0; i < _widthsArrayBase; i++) {
  313.             _widthsArray[i] = 0;
  314.         }
  315.         for (i = 1, index = _widthsArrayBase; i < count; i++, index++) {
  316.             _widthsArray[index] = parseInt((String)widthsInfo[i]);
  317.         }
  318.  
  319.         if (_widthsArray[' '] == 0) {
  320.             _widthsArray[' '] = 5;
  321.         }
  322.     }
  323.  
  324.     java.awt.Image croppedImage(int x, int y, int width, int height) {
  325.         java.awt.Image  croppedImage;
  326.  
  327.         croppedImage = AWTCompatibility.awtApplet().createImage(
  328.             new FilteredImageSource(_glyphsImage.awtImage.getSource(),
  329.             new CropImageFilter(x, y, width, height)));
  330.  
  331.         return croppedImage;
  332.     }
  333.  
  334.     void _loadGlyphs(java.net.URL fontURL) {
  335.         java.net.URL                            glyphURL;
  336.         Image                                glyphsImage, newImage;
  337.         java.awt.image.ImageFilter              imageChopper;
  338.         FilteredImageSource                     filteredImageSource;
  339.         java.awt.Image                          awtImage;
  340.         int                                     i, x, c;
  341.  
  342.       /* description file */
  343.         try {
  344.             glyphURL = new URL(fontURL, _name + ".font/" + GLYPHS);
  345.         } catch (Exception e) {
  346.             System.err.println(
  347.                 "Font.init() - Trouble creating font glyph URL " +
  348.                         fontURL + _name + ".font/" + GLYPHS + " : " + e);
  349.             _type = INVALID;
  350.             return;
  351.         }
  352.  
  353.         _glyphsImage = Bitmap.bitmapFromURL(glyphURL);
  354.         _glyphsImage.loadData();
  355.  
  356.         if (_glyphsImage == null || !_glyphsImage.isValid()) {
  357.             System.err.println(
  358.                 "Font._loadGlyphs() - Trouble loading glyphs for " + _name);
  359.             return;
  360.         }
  361.  
  362.         _glyphsImage.loadData();
  363.  
  364.         for (i = _widthsArrayBase, x = 0; i < _widthsArray.length; i++) {
  365.             awtImage = croppedImage(x, 0, _widthsArray[i],
  366.                                      _glyphsImage.height());
  367.             _glyphVector.addElement(
  368.                                 AWTCompatibility.bitmapForAWTImage(awtImage));
  369.             newImage = (Image)_glyphVector.lastElement();
  370.  
  371.             x += _widthsArray[i];
  372.         }
  373.     }
  374.  
  375.     /** Returns <b>true</b> if the Font is valid.  A Font will not
  376.       * be valid if there were problems creating its java.awt.Font (for local
  377.       * Fonts), or there was a problem downloading the Font's resources
  378.       * (for downloadable Fonts).
  379.       */
  380.     boolean isValid() {
  381.         return (_type != INVALID);
  382.     }
  383.  
  384.     /** Returns <b>true</b> if the Font was downloaded from the Applet's
  385.       * web server.
  386.       */
  387.     boolean wasDownloaded() {
  388.         return (_type == DOWNLOADED);
  389.     }
  390.  
  391.     /** Returns the Font's font metrics. */
  392.     public FontMetrics fontMetrics() {
  393.         if (_metrics == null) {
  394.             _metrics = new FontMetrics(this);
  395.         }
  396.  
  397.         return _metrics;
  398.     }
  399.  
  400.     /** Returns the Font's family. */
  401.     public String family() {
  402.         if (_type == INVALID) {
  403.             return "";
  404.         }
  405.  
  406.         if (_awtFont != null) {
  407.             return _awtFont.getFamily();
  408.         } else {
  409.             return (String)_description.get(FAMILY);
  410.         }
  411.     }
  412.  
  413.     /** Returns the Font's name.  For local fonts this is the font name,
  414.       * such as "Helvetica".
  415.       */
  416.     public String name() {
  417.         if (_type == INVALID) {
  418.             return "";
  419.         }
  420.  
  421.         return _name;
  422.     }
  423.  
  424.     /** Returns the integer representation of the Font's style. */
  425.     public int style() {
  426.         if (_type == INVALID) {
  427.             return -1;
  428.         }
  429.  
  430.         if (_awtFont != null) {
  431.             return _awtFont.getStyle();
  432.         } else {
  433.             return parseInt((String)_description.get(STYLE));
  434.         }
  435.     }
  436.  
  437.     /** Returns the Font's point size. */
  438.     public int size() {
  439.         if (_type == INVALID) {
  440.             return -1;
  441.         }
  442.  
  443.         if (_awtFont != null) {
  444.             return _awtFont.getSize();
  445.         } else {
  446.             return parseInt((String)_description.get(SIZE));
  447.         }
  448.     }
  449.  
  450.     /** Returns <b>true</b> if the Font's style is "plain." */
  451.     public boolean isPlain() {
  452.         return ((style() == PLAIN) ? true : false);
  453.     }
  454.  
  455.     /** Returns <b>true</b> if the Font's style is "bold." */
  456.     public boolean isBold() {
  457.         return (((style() & BOLD) > 0) ? true : false );
  458.     }
  459.  
  460.     /** Returns <b>true</b> if the Font's style is "italic."
  461.       */
  462.     public boolean isItalic() {
  463.         return (((style() & ITALIC) > 0) ? true : false );
  464.     }
  465.  
  466.     /** Returns the Font's "glyph vector," its collection of images that
  467.       * comprise the font.  This method is valid only with a downloaded font.
  468.       */
  469.     Vector glyphVector() {
  470.         return _glyphVector;
  471.     }
  472.  
  473.     String _stringValueFromDescription(String keyName) {
  474.         if (keyName == null || _description == null) {
  475.             return "";
  476.         }
  477.  
  478.         return (String)_description.get(keyName);
  479.     }
  480.  
  481.     int _intValueFromDescription(String keyName) {
  482.         if (keyName == null || _description == null) {
  483.             return 0;
  484.         }
  485.  
  486.         return parseInt((String)_description.get(keyName));
  487.     }
  488.  
  489.     /** Returns the Font's string representation. The string takes the form
  490.       * "Fontname.style.size" and is suitable for use in Font.fontNamed().
  491.       */
  492.     public String toString() {
  493.         String          styleString;
  494.  
  495.         if (_type == INVALID || wasDownloaded()) {
  496.             return _name;
  497.         }
  498.  
  499.         if (isBold()) {
  500.             if (isItalic()) {
  501.                 styleString = "BoldItalic";
  502.             } else {
  503.                 styleString = "Bold";
  504.             }
  505.         } else if (isItalic()) {
  506.             styleString = "Italic";
  507.         } else {
  508.             styleString = "Plain";
  509.         }
  510.  
  511.         return family() + ":" + styleString + ":" + size();
  512.     }
  513.  
  514.     /** Describes the Font class' information.
  515.       * @see Codable#describeClassInfo
  516.       */
  517.     public void describeClassInfo(ClassInfo info) {
  518.         info.addClass("netscape.application.Font", 1);
  519.         info.addField(NAME_KEY, STRING_TYPE);
  520.         info.addField(STYLE_KEY, INT_TYPE);
  521.         info.addField(SIZE_KEY, INT_TYPE);
  522.     }
  523.  
  524.     /** Encodes the Font instance by name.
  525.       * @see Codable#encode
  526.       */
  527.     public void encode(Encoder encoder) throws CodingException {
  528.         encoder.encodeString(NAME_KEY, name());
  529.         encoder.encodeInt(STYLE_KEY, style());
  530.         encoder.encodeInt(SIZE_KEY, size());
  531.     }
  532.  
  533.     /** Decodes the Font instance by name.
  534.       * @see Codable#decode
  535.       */
  536.     public void decode(Decoder decoder) throws CodingException {
  537.         Font    font;
  538.         String  name;
  539.         int style, size;
  540.  
  541.         name = decoder.decodeString(NAME_KEY);
  542.         style = decoder.decodeInt(STYLE_KEY);
  543.         size = decoder.decodeInt(SIZE_KEY);
  544.  
  545.         font = fontNamed(name, style, size);
  546.  
  547.         // Only replace the object if we are not a subclass of Font.
  548.  
  549.         if (getClass() == fontClass()) {
  550.             decoder.replaceObject(font);
  551.         } else {
  552.             _name = font._name;
  553.             _type = font._type;
  554.             _awtFont = font._awtFont;
  555.             nameFont(_name, this);
  556.         }
  557.     }
  558.  
  559.     /** Finishes the Font's decoding.
  560.       * @see Codable#finishDecoding
  561.       */
  562.     public void finishDecoding() throws CodingException {
  563.     }
  564. }
  565.